﻿using CacheManager.Core;
using K9Nano.Caching;
using K9Nano.Caching.CacheManager;
using K9Nano.Dependency;
using K9Nano.Domain.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace K9Nano;

public static class K9NanoCoreStartupExtensions
{
    public static IK9AppBuilder AddK9NanoCore(this IServiceCollection services,
        Action<IK9AppBuilder> buildAction,
        Action<K9Options> configure)
    {
        services.Configure(configure);

        services.RegisterByConvention();

        services.AddHttpContextAccessor();

        services.AddSingleton<IIocHelper>(new DefaultIocHelper(services));

        var app = new K9AppBuilder(services);

        buildAction?.Invoke(app);

        return app;
    }

    public static IK9AppBuilder UseTypeCacheManager(this IK9AppBuilder builder, Action<CachingOptions> setupAction)
    {
        var options = new CachingOptions();
        setupAction(options);
        var redisConnection = options.ConnectionString;
        builder.Services.AddCacheManagerConfiguration(configure: config =>
        {
            var part = config
                 .WithUpdateMode(CacheUpdateMode.Up)
                 .WithMicrosoftMemoryCacheHandle();

            if (!string.IsNullOrWhiteSpace(options.ConnectionString))
            {
                part.And
                    .WithRedisConfiguration("redis", redisConnection, enableKeyspaceNotifications: options.EnableKeyspaceNotifications)
                    .WithRedisBackplane("redis")
                    .WithRedisCacheHandle("redis", true);
            }
            config.WithSystemTextJsonSerializer();
        });
        builder.Services.AddCacheManager();
        builder.Services.Configure<CachingOptions>(setupAction);
        builder.Services.AddSingleton(typeof(ITypedCache<>), typeof(TypedCache<>));
        return builder;
    }

    internal static ConfigurationBuilderCachePart WithSystemTextJsonSerializer(
        this ConfigurationBuilderCachePart part)
    {
        return part.WithSerializer(typeof(SystemTextJsonSerializer), new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
        });
    }

    public static IK9AppBuilder UseFontendRoutes(this IK9AppBuilder builder, IEnumerable<KeyValuePair<string, string>> routes)
    {
        foreach (var item in routes)
        {
            FrontendRoutes.Routes.Add(item.Key, item.Value);
        }
        return builder;
    }


    public static IApplicationBuilder UseStorageAsStaticFiles(
      this IApplicationBuilder app)
    {
        var options = app.ApplicationServices.GetRequiredService<IOptions<K9Options>>().Value;

        string pathRoot;
        if (Path.IsPathRooted(options.StorageRoot))
        {
            pathRoot = options.StorageRoot;
        }
        else
        {
            pathRoot = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, options.StorageRoot);
        }
        Directory.CreateDirectory(pathRoot);

        app.UseStaticFiles(new StaticFileOptions
        {
            RequestPath = options.StorageRequestPath.TrimEnd('/'),
            FileProvider = new PhysicalFileProvider(pathRoot)
        });
        return app;
    }
}